名称

loader.efi——UEFI内核加载器

描述

在UEFI系统上,loader.efi 加载内核。

boot1.efi(8) 用于在将 loader.efi 放置在UFS或ZFS文件系统中时加载它。或者,当使用 efibootmgr(8) 配置时,或者当直接放置为 uefi(8) 中描述的默认引导程序时,可以直接使用 loader.efi 。当使用 bsdinstall(8) 构建系统时,将直接使用 loader.efi

控制台(console)注意事项

EFI BIOS提供了一个通用控制台。在 loader.efi 中,这是通过使用控制台变量指定“efi”来选择的。loader.efi 检查 8be4df61-93ca-11d2-aa0d-00e098032b8c-ConOut UEFI环境变量,以猜测“efi”控制台指向什么。 loader.efi 将其提示和菜单输出到ConOut指定的所有位置。然而,当存在多个控制台时,FreeBSD内核有一个限制。内核输出到所有配置的控制台。只有主控制台会从 rc(8) 系统获取日志消息,并提示输入 geli(8) 密码等信息。如果 loader.efi 首先找到一个视频设备,那么 loader.efi 告诉内核使用视频控制台作为主要设备。同样,如果串行设备位于ConOut列表中的第一个,则串行端口将是主控制台。

如果没有ConOut变量,则尝试串行和视频。 loader.efi 使用默认波特率的“efi”控制台用于视频(可能工作也可能不工作),使用“comconsole”用于COM1上的串行。内核将使用双控制台,如果检测到UEFI图形设备,则视频控制台为主控制台,否则串行控制台为主控制台。

在x86平台上,如果您希望在EFI BIOS不支持时将加载程序的输出重定向到串行端口,或者重定向到EFI BIOS将其输出重定向到的非串行端口,请将控制台设置为“comconsole”。默认端口为COM1,I/O地址为0x3f8。

如果您将控制台设置为 efi,comconsole ,您将在EFI控制台和串行端口上获得输出。如果这会导致字符加倍,请将控制台设置成“efi”,因为您的EFI BIOS已经重定向到串行端口。

如果EFI BIOS重定向串行端口,您可能需要告诉内核要使用哪个地址。EFI使用ACPI的UID来标识串行端口,但 loader.efi 没有ACPI解析器,因此无法将其转换为I/O端口。FreeBSD内核在解码ACPI资源之前会初始化其控制台。FreeBSD内核将查看 hw.uart.console 变量来设置其串行控制台。它的格式应该在 uart(4) 中描述,但没有。使用正确的端口地址将其设置为“io:0x3f8,br:115200”。PCI或内存映射端口超出了本手册页的范围。

在IBM PC兼容系统上,串行端口的分配如下:

虽然COM3和COM4可以变化。

主控制台

使用引导标志(boot flags)设置主控制台。这些命令行参数为内核设置了相应的标志。这些标志可以通过将加载程序环境变量设置为 yesno 来控制。引导标志可以在引导命令的命令行上设置。在内核中,RB_ 标志用于控制行为,有时是以特定于架构的方式,并被包含在内以帮助发现本文档中未涵盖的任何行为。

以下标志决定了主控制台:

loader.efi 不实现查看 -P 功能,如果连接了键盘,则使用视频控制台,否则使用串行控制台。

其他环境变量

loader.efi 在启动早期从EFI分区的 /efi/freebsd/loader.env 加载一些额外的变量。这里只能设置简单的变量。指定根文件系统可能很有用:

分阶段溢出(Staging Slop)

内核必须解析固件内存映射表,以了解它可以使用什么内存。由于它必须分配内存才能做到这一点, loader.efi 确保在加载所有内容(内核、模块和元数据)后,有额外的可用内存,称为“slop”(溢出),供内核引导内存分配器。

默认情况下,amd64保留8MB。staging_slop 命令允许调整溢出大小。它只接受一个参数,即溢出的大小(以字节为单位)。

amd64 Nocopy

loader.efi 将内核加载到低于4GB的2MB内存中。它无法加载到固定地址,因为UEFI固件可能会在运行时保留任意内存供其使用。在FreeBSD 13.1之前,内核保留了旧的BIOS引导协议,即以2MB的速度加载。在启动这些内核之前,必须将其从加载位置复制到2MB。 copy_staging 命令用于为较旧的内核启用此复制。它接受一个参数,该参数可以是以下之一:

Arm64加载器从一开始就在“nocopy”模式下运行,因此该平台上没有 copy_staging 命令。Riscv、32位arm和arm64始终在任何2MB对齐的位置加载,因此不提供 copy_staging

注意。i386和amd64上的BIOS加载器将暂存区从物理地址2M开始,然后为低1G启用具有相同映射的分页。 loader.efi 的初始端口遵循将控制权移交给内核的相同方案,因为它避免了对加载器/内核移交协议和内核页表引导的修改。 这种方法与UEFI规范不兼容,并且实际上在许多板上造成了麻烦,因为UEFI固件可以自由使用任何内存来满足自己的需求。像 loader.efi 这样的应用程序必须只使用通过引导接口显式分配的内存。原始方式也可能破坏UEFI运行时接口数据。 最终,loader.efi 和内核得到了改进,以避免这个问题。

amd64故障

由于它在x86保护模式下执行,amd64版本的 loader.efi 容易因程序员错误和内存损坏而出现CPU故障。为了使调试此类故障更容易,amd64 loader.efi 可以提供故障发生时CPU状态的详细报告。

grab_faults 命令直接在IDT中安装故障处理程序,避免使用UEFI调试接口 EFI_DEBUG_SUPPORT_PROTOCOL.RegisterExceptionCallback() 。该接口可供UEFI环境中的高级调试器使用。 ungrab_faults 命令尝试卸载故障处理程序,将TSS和IDT CPU表恢复到安装前的状态。 fault 命令通过执行 ud2 处理器指令,在 loader.efi 环境中产生故障以进行测试。

文件

/boot/loader.efi UEFI内核加载器在系统中的位置。

EFI系统分区

loader.efi 安装在ESP(EFI系统分区)的以下位置之一:

ESP装载点的默认位置记录在 hier(7) 中。

示例

更新ESP上的loader.efi

以下示例显示了如何在ESP上安装新的 loader.efi 。由于安装、设置和情况的多样性,确切的位置很复杂。在本节中,所有小写的路径都是Unix路径。所有大写的路径都是相对于ESP装载点的,尽管它们在您的系统上可能显示为小写,因为ESP的FAT文件系统不区分大小写。

找到ESP,它有自己的分区类型“efi”:

此系统上的ESP名称为 nda0p1 。默认情况下,这将被挂载在 /boot/efi 上。检查:

如果它没有挂载,你需要使用以下命令挂载它:

efibootmgr(8) 报告了我们从何处启动。

通常有几个选项,具体取决于BIOS。我们启动的条目在行首标有“+”,如上所示。因此,在这种情况下,此固件使用ESP的 /EFI/FREEBSD/LOADER.EFI 。通常情况下,它将是UEFI“默认”加载程序,这因架构而异。

但是,必须小心:一些多引导环境依赖于特殊的 bootXXX.efi 才能运行。在更新 bootXXX.efi 文件之前,请确保它是FreeBSD引导加载程序,然后再进行更新:

bsdinstall(8)loader.efi 复制到默认名称(如果以前没有)。在更新之前检查它们是否是副本(使用上表替换X64):

复制加载器:

用正确的路径替换示例中的所有大写部分。

如果ESP路径为 /FREEBSD/LOADER.EFILOADER.EFIBOOTX64.EFI 在cmp步骤中是相同的,将加载器复制到默认位置:

最后,如果您挂载了ESP,您可能希望卸载它。

参见

BUGS

非x86串行控制台处理更令人困惑,文档也更少。

有时,当串行端口速度未设置时,会使用9600。其他时候,由于速度与默认值保持不变,结果通常为115200。

U-Boot实现了UEFI标准的一个子集。某些版本不支持获取加载程序变量,因此 efibootmgr 可能无法工作。此外,armv7或riscv不支持 efibootmgr 。在这些情况下,用户必须了解引导的内容才能正确更新(在大多数情况下,它将是FreeBSD路径和UEFI默认路径,因此如果那里有加载器,只需将 loader.efi 复制到那里)。通常,在这些嵌入式情况下,只有一个 .efi 文件( loader.efiloader.efi 的副本)。此文件的路径通常是上面的默认可移动路径。

在UEFI上引导多个操作系统的管理差异很大,因此在更新UEFI默认加载程序时要格外小心。

旧的、现已过时的 boot1.efi 在FreeBSD 10及更早版本中作为 bootx64.efi 安装。由于它的功能非常有限,我们默认创建了非常小的ESP。现代 loader.efi 不适合。但是,如果旧的 boot1.efi 仍然有效,则无需对其进行更新,因为它会将 boot/boot/loader.efi 与进行installworld更新的副本链接起来。